package cn.kent.high.juc.lock.reentrantLock;

import java.util.concurrent.locks.StampedLock;

/**
 * 这个类在 StampedLock 注释中 - 是一种使用用例
 * 用于维护简单二维点的类
 *
 * StampedLock和ReentrantReadWriteLock类似，只是前者提供的是不可重入锁。但是前者通过提供乐观锁在多线程多读的情况下提供更好的性能。
 *      因为获取乐观锁时不需要进行CAS操作设置状态，只是简单的测试状态
 */
public class Point {
    // 成员变量
    private double x, y;
    // 锁实例
    private final StampedLock sl = new StampedLock();

    // 排它锁 | 写锁
    void move(double deltaX, double deltaY) { // an exclusively locked method
        long stamp = sl.writeLock();
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            sl.unlockWrite(stamp);
        }
    }

    //乐观读锁
    double distanceFromOrigin() { // A read-only method
        long stamp = sl.tryOptimisticRead();
        double currentX = x, currentY = y;
        if (!sl.validate(stamp)) {
            stamp = sl.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                sl.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }

    // 使用悲观锁获取读锁，并尝试转换为写锁
    void moveIfAtOrigin(double newX, double newY) { // upgrade
        // Could instead start with optimistic, not read mode
        // 可以使用读锁替换
        long stamp = sl.readLock();
        try {
            while (x == 0.0 && y == 0.0) {
                long ws = sl.tryConvertToWriteLock(stamp);
                if (ws != 0L) {
                    stamp = ws;
                    x = newX;
                    y = newY;
                    break;
                } else {
                    sl.unlockRead(stamp);
                    stamp = sl.writeLock();
                }
            }
        } finally {
            sl.unlock(stamp);
        }
    }
}